import {BaseGame} from "./BaseGame";
import {GameMode} from "./GameMode";
import GameMainEntry from "../Base/GameMainEntry";
import {UIStruct} from "../UI/UIStruct";
import {EventID} from "../Event/EventID";
import GameEventArgs from "../../AzraelFrameWork/src/Event/GameEventArgs";
import {Constant} from "../Definition/Constant";
import RigidBody = cc.RigidBody;
import ccclass = cc._decorator.ccclass;
import {ReferencePool} from "../../AzraelFrameWork/src/Base/ReferencePool/ReferencePool";

export class StartGameArg extends GameEventArgs {
    public static Create(): StartGameArg {
        let eventagrs: StartGameArg = ReferencePool.Acquire(StartGameArg);
        return eventagrs;
    }

    Clear(): void {
    }

    Id(): number {
        return EventID.startgame;
    }

}

export class ScoreTextGameArgs extends GameEventArgs {
    public static Create(score: number): ScoreTextGameArgs {
        let eventagrs: ScoreTextGameArgs = ReferencePool.Acquire(ScoreTextGameArgs);
        eventagrs.score = score;
        return eventagrs;
    }

    private score: number;

    public get Score(): number {
        return this.score;
    }

    Clear(): void {
        this.score = 0;
    }

    Id(): number {
        return EventID.ScoreText;
    }

}

@ccclass
export class NormalGame extends cc.Component implements BaseGame {
    private static _circle_prefab: cc.Prefab;
    private static _star_prefab: cc.Prefab;

    public static createCircle(): cc.Node {
        return cc.instantiate(this._circle_prefab);
    }

    private _config: {};
    private _score: number;
    private _hitcount: number;
    private _isstart: boolean;
    private _isover: boolean;
    private _starsPool:cc.NodePool;
    set score(value: number) {
        this._score = value;
    }

    get score(): number {
        return this._score;
    }

    GameOver(): boolean {
        return this._isover;
    }


    Init(): void {
        let self = this;
        this._starsPool = new cc.NodePool();
        let manager = cc.director.getCollisionManager();
        manager.enabled = true;
        manager.enabledDrawBoundingBox = true;
        manager.enabledDebugDraw = true;
        cc.director.getPhysicsManager().enabled = true;
        cc.director.getPhysicsManager().debugDrawFlags = cc.PhysicsManager.DrawBits.e_aabbBit |
            cc.PhysicsManager.DrawBits.e_jointBit |
            cc.PhysicsManager.DrawBits.e_shapeBit
        ;
        GameMainEntry.Resource.load("Prefabs/circle", cc.Prefab, (error, assets) => {
            if (error) {
                cc.error(error);
                return;
            }
            NormalGame._circle_prefab = assets as cc.Prefab;
        });
        GameMainEntry.Resource.load("Prefabs/star", cc.Prefab, (error, assets) => {
            if (error) {
                cc.error(error);
                return;
            }
            NormalGame._star_prefab = assets as cc.Prefab;
            self._starsPool.put(cc.instantiate(NormalGame._star_prefab));
        });
        GameMainEntry.Resource.loadJsonAsset("Configs/config", (error, assets) => {
            if (error) {
                cc.error(error);
                return;
            }
            let jsonAsset: cc.JsonAsset = assets as cc.JsonAsset;
            self._config = jsonAsset.json;
            this.schedule(this.IntervalStars,this._config["duration"]);
        });

        this._isstart = false;
        this._isover = false;
        this._score = 0;
        GameMainEntry.UI.OpenUIForm(UIStruct.UI_fight);
        GameMainEntry.Event.Subscribe(EventID.startgame, this.startGame.bind(this));
        GameMainEntry.Event.Subscribe(EventID.Score, this.updateScore.bind(this));
        GameMainEntry.Event.Subscribe(EventID.HitCount, this.upadteHitCount.bind(this));
        GameMainEntry.Event.Subscribe(EventID.gameover, this.gameOver.bind(this));
        this.scheduleOnce(() => {
            GameMainEntry.Event.Fire(this, StartGameArg.Create());
        }, 3);

    }

    Shutdown(): void {
        GameMainEntry.Event.Unsubscribe(EventID.startgame, this.startGame.bind(this));
        GameMainEntry.Event.Unsubscribe(EventID.Score, this.updateScore.bind(this));
        GameMainEntry.Event.Unsubscribe(EventID.HitCount, this.upadteHitCount.bind(this));
        GameMainEntry.Event.Unsubscribe(EventID.gameover, this.gameOver.bind(this));
        this.unschedule(this.IntervalStars);
        this._starsPool.clear();
    }

    Update(elapseSeconds: number, realElapseSeconds: number): void {
    }

    private startGame(sender, e): void {
        this._isstart = true;
        let circle: cc.Node = NormalGame.createCircle();
        let rigidBody: RigidBody = circle.getComponent(RigidBody);
        circle.setParent(GameMainEntry.UI.getCanvas().node);
        rigidBody.linearVelocity = Constant.speed;
    }

    GameMode(): GameMode {
        return GameMode.Normal;
    }


    private updateScore(sender, e) {
        this._score += 1;
        sender.node.active = false;
        this._starsPool.put(sender.node);
        GameMainEntry.Event.Fire(this, ScoreTextGameArgs.Create(this._score));
    }

    private upadteHitCount(sender, e) {
        this._hitcount += 1;
    }


    private gameOver(sender, e) {
        this._isover = true;
        if(sender){
            sender.node.destroy();
        }
        cc.log("gameover");
    }

    IntervalStars(dt:number){
        let arr:cc.Vec2[] = this.CreateStars(1);
        for (let j = 0; j < arr.length;j++){
            if(this._starsPool.size() <= 0){
                this._starsPool.put(cc.instantiate(NormalGame._star_prefab));
            }
            let star:cc.Node = this._starsPool.get();
            star.active = true;
            star.setParent(GameMainEntry.UI.getCanvas().node);
            star.setPosition(arr[j]);
        }
    }


    CreateStars(count: number):cc.Vec2[] {
        let arr: {x,y}[] = this._config["random"].slice();
        let stars:cc.Vec2[] = [];
        for (let i = 0; i < count;++i){
            let index:number = Math.ceil( Math.random() * arr.length);
            if(index < arr.length){
                stars.push(cc.v2(arr[index].x,arr[index].y));
                arr.splice(index,1);
            }
        }
        return stars;
    }


}